﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the Microsoft Public License (Ms-PL).
// See accompanying file License.txt or copy at http://mews.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mews.Application
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Windows.Forms;

    using Mews.Application.Properties;
    using Mews.Net.Nntp.Cache;
    using Microsoft.Win32;

    /// <summary>The class containing the entry point of the program.</summary>
    internal static class Program
    {
        private const string ApplicationName = "Mews";
        private const string RegistryKey = "HKEY_CURRENT_USER\\Software\\" + ApplicationName;
        private const string DataDirectoryValueName = "DataDirectory";

        [MTAThread]
        private static void Main()
        {
            AppDomain.CurrentDomain.UnhandledException += OnCurrentDomain_UnhandledException;
            string tempDirectory;

            using (var cache = GetOrCreateCache(out tempDirectory))
            {
                if (cache != null)
                {
                    Application.Run(new MainForm(tempDirectory, cache));
                }
            }
        }

        private static void OnCurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var exception = e.ExceptionObject as Exception;

            if (exception is IncompatibleCacheException)
            {
                ShowError(
                    Resources.IncompatibleDatabaseCaption, Resources.IncompatibleDatabaseText, GetDataDirectory());
            }
            else
            {
                var errorFile = Path.Combine(GetDataDirectory(), "UnexpectedError.txt");

                using (var writer = File.CreateText(errorFile))
                {
                    while (exception != null)
                    {
                        writer.WriteLine(exception.Message);
                        writer.WriteLine(exception.StackTrace);
                        writer.WriteLine();
                        writer.WriteLine();
                        exception = exception.InnerException;
                    }
                }

                ShowError(Resources.UnexpectedErrorCaption, Resources.UnexpectedError, errorFile);
            }

            Application.Exit();
        }

        private static Cache GetOrCreateCache(out string tempDirectory)
        {
            bool subsequentAttempt = false;
            tempDirectory = null;

            do
            {
                var dataDirectory = GetDataDirectory();

                if (dataDirectory == null)
                {
                    if (subsequentAttempt)
                    {
                        // The value still does not exist in the registry, despite having been set once. Something must
                        // have gone horribly wrong -> bail out
                        return null;
                    }
                }
                else
                {
                    string cacheDirectory = Path.Combine(dataDirectory, "Cache");
                    tempDirectory = Path.Combine(Path.Combine(dataDirectory, "Render"), "Temp");

                    try
                    {
                        using (var cacheGuard =
                            ScopeGuard.Create(new Cache(cacheDirectory, new UserSpecificCryptoProvider())))
                        {
                            if (cacheGuard.Resource.ShouldCompact &&
                                (FormHelper.ShowDialog(new MaintenanceForm(cacheGuard.Resource)) != DialogResult.OK))
                            {
                                return null;
                            }

                            cacheGuard.Dismiss();
                            return cacheGuard.Resource;
                        }
                    }
                    catch (FileNotFoundException)
                    {
                        // The data directory does not contain the expected files
                        if (subsequentAttempt)
                        {
                            Directory.CreateDirectory(dataDirectory);

                            if ((Directory.GetDirectories(dataDirectory).Length == 0) &&
                                (Directory.GetFiles(dataDirectory).Length == 0))
                            {
                                Cache.CreateCache(cacheDirectory);
                                var cache = new Cache(cacheDirectory, new UserSpecificCryptoProvider());
                                cache.AddHost("news.mozilla.org", 119).AddGroup(
                                    "mozilla.test", "Mozilla Test", 100, 2000);
                                return cache;
                            }

                            MessageBoxHelper.ShowError(
                                Resources.DataDirectoryNotEmptyText, Resources.DataDirectoryNotEmptyCaption);
                        }
                    }
                }

                subsequentAttempt = true;
            }
            while (SetDataDirectory());

            return null;
        }

        private static void ShowError(string caption, string messageFormat, params object[] args)
        {
            MessageBoxHelper.ShowError(string.Format(CultureInfo.InvariantCulture, messageFormat, args), caption);
        }

        private static string GetDataDirectory()
        {
            return Registry.GetValue(RegistryKey, DataDirectoryValueName, null) as string;
        }

        private static bool SetDataDirectory()
        {
            using (var dataDirectoryForm = new DataDirectoryForm(ApplicationName))
            {
                if (dataDirectoryForm.ShowDialog() == DialogResult.OK)
                {
                    Registry.SetValue(
                        RegistryKey, DataDirectoryValueName, dataDirectoryForm.SelectedStorageLocation);
                }

                // We deliberately don't reset the cursor to a wait cursor here, because it doesn't seem to change until
                // the main form is shown
                return dataDirectoryForm.DialogResult == DialogResult.OK;
            }
        }
    }
}
